/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.struct.table.base

import com.gitee.wsl.ext.any.ifNullValue
import com.gitee.wsl.serialization.json.OptionalInput
import com.gitee.wsl.text.CDataText
import kotlin.reflect.KClass

/**
 * 记录了值所对应的源码位置
 */
class ValueWithLocation protected constructor(val loc: SourceLocation?, val value: Any?) {

    private fun readResolve(): Any {
        if (value == null) {
            if (loc == null) return NULL_VALUE
        } else if (value === OptionalInput.Undefined) {
            return UNDEFINED_VALUE
        }
        return this
    }

    override fun toString(): String {
        return value.toString() + "@loc=" + loc
    }

    val isUndefined: Boolean
        get() = value === OptionalInput.Undefined

    val isNull: Boolean
        get() = value == null || value === OptionalInput.Undefined

    val isEmpty: Boolean
        get() {
            if (value === OptionalInput.Undefined || value == null) return true
            if (value is String) {
                return value.isEmpty();
            }
            return false
        }

    fun asString(): String {
        return value.toString()
    }

    fun asString(defaultValue: String?): String? {
        var str: String? = asString()
        if (str == null) str = defaultValue
        return str
    }

    val valueClass: KClass<*>?
        get() = value.ifNullValue(null,value!!::class)

    val isCDataText: Boolean
        get() = value is CDataText

    val isStringValue: Boolean
        get() = value is String || value is CDataText

    /*fun toPrimitiveBoolean(): Boolean {
        if (value === OptionalInput.Undefined) return false
        if (isCDataText) return ConvertHelper.toPrimitiveBoolean(value.toString())
        return ConvertHelper.toPrimitiveBoolean(value)
    }*/

    val location: SourceLocation?
        get() = loc

    fun addRef(ref: String): ValueWithLocation {
        if (ref.isEmpty()) return this

        if (loc == null) return this

        val loc: SourceLocation = loc.addRef(ref)
        return of(loc, value)
    }

    fun trim(): ValueWithLocation {
        val str = asString() ?: return this

        val trimmed = str.trim { it <= ' ' }
        if (trimmed == str) return this

        return of(loc, trimmed)
    }

    /*fun deepClone(): ValueWithLocation {
        if (this.value == null) return this

        val cloned: Any = CloneHelper.deepClone(value)
        if (cloned === value) return this
        return newValueWithLocation(loc, cloned)
    }*/

    protected fun newValueWithLocation(loc: SourceLocation?, value: Any?): ValueWithLocation {
        return ValueWithLocation(loc, value)
    }

    companion object {

        val NULL_VALUE: ValueWithLocation = ValueWithLocation(null, null)
        val UNDEFINED_VALUE: ValueWithLocation = ValueWithLocation(null, OptionalInput.Undefined)

        fun of(loc: SourceLocation?, value: Any?): ValueWithLocation {
            if(loc == null && value == null) return NULL_VALUE
            if (value === OptionalInput.Undefined) return UNDEFINED_VALUE
            if (value is ValueWithLocation) return value
            return ValueWithLocation(loc, value)
        }
    }
}